#include "sql/expr/tuple.h"

bool match_field(RelAttr &condition_attr, Field &field) {
    return strcmp(condition_attr.relation_name, field.table_name()) == 0 && strcmp(condition_attr.attribute_name, field.field_name()) == 0;
}

bool match_field(Field &first, Field &second) {
    return strcmp(first.table_name(), second.table_name()) == 0 && strcmp(first.field_name(), second.field_name()) == 0;
}

bool match_tuple_value(const TupleValue *first, const TupleValue *second, const CompOp compare) {
    bool result = false;
    switch (compare) {
    case EQUAL_TO:
        result = (*first == *second);
        break;
    case NOT_EQUAL:
        result = !(*first == *second);
        break;
    case LESS_EQUAL:
        result = (*first == *second || *first < *second);
        break;
    case GREAT_EQUAL:
        result = (*first == *second || *first > *second);
        break;
    case LESS_THAN:
        result = (*first < *second);
        break;
    case GREAT_THAN:
        result = (*first > *second);
        break;
    }
    return result;
}

void TupleSet::to_string(std::ostream &os) {
    // print header
    const int cell_num = schema_.get_length();
    Field field;
    for (int i = 0; i < cell_num; i++) {
        if (i != 0) {
            os << " | ";
        }
        schema_.get(i, field);
        os << field.table_name() << "." << field.field_name();
    }
    if (cell_num > 0) {
        os << '\n';
    }

    // print data
    TupleDataRow data_row;
    for (int row = 0; row < data_.size(); row++) {
        get_data_row(row, data_row);
        std::shared_ptr<TupleValue> tuple_value;
        for (int i = 0; i < cell_num; i++) {
            if (i != 0) {
                os << " | ";
            }
            data_row.get(i, tuple_value);
            tuple_value->to_string(os);
        }
        if (cell_num > 0) {
            os << '\n';
        }
    }
}

TupleSet TupleSet::merge_tuple_set(TupleSet &tuple_set, std::vector<Condition> &join_conditions) {
    TupleSet final_set;
    TupleSchema final_schema;

    // 合并的TupleSet
    final_schema.set_schema(this->schema_);
    final_schema.merge_schema(tuple_set.schema());
    final_set.set_schema(final_schema);

    // 找到要比较的列的索引, 统一变成main表在左边的形式
    std::vector<int> first_index;
    std::vector<int> second_index;
    std::vector<CompOp> compare_op;
    for (int cond_i = 0; cond_i < join_conditions.size(); cond_i++) {
        int first_cond_index_left = -1, first_cond_index_right = -1;
        int second_cond_index_left = -1, second_cond_index_right = -1;
        for (int i = 0; i < this->schema().get_fields().size(); i++) {
            if (first_cond_index_left == -1 && match_field(join_conditions[cond_i].left_attr, this->schema().get_field_by_index(i))) {
                first_cond_index_left = i;
                break;
            }
            if (first_cond_index_right == -1 && match_field(join_conditions[cond_i].right_attr, this->schema().get_field_by_index(i))) {
                first_cond_index_right = i;
                break;
            }
        }
        for (int i = 0; i < tuple_set.schema().get_fields().size(); i++) {
            if (second_cond_index_left == -1 && match_field(join_conditions[cond_i].left_attr, tuple_set.schema().get_field_by_index(i))) {
                second_cond_index_left = i;
                break;
            }
            if (second_cond_index_right == -1 && match_field(join_conditions[cond_i].right_attr, tuple_set.schema().get_field_by_index(i))) {
                second_cond_index_right = i;
                break;
            }
        }
        //如果该条件跟现在合并的两表没有关系
        if ((first_cond_index_left == -1 && first_cond_index_right == -1) || (second_cond_index_left == -1 && second_cond_index_right == -1)) {
            continue;
        }

        //因为连接条件一定来自两个表，所以必定为一左一右
        if (first_cond_index_left != -1 && second_cond_index_right != -1) {
            first_index.push_back(first_cond_index_left);
            second_index.push_back(second_cond_index_right);
            compare_op.push_back(join_conditions[cond_i].comp);
        } else if (first_cond_index_right != -1 && second_cond_index_left != -1) {
            first_index.push_back(first_cond_index_right);
            second_index.push_back(second_cond_index_left);

            switch (join_conditions[cond_i].comp) {
            case EQUAL_TO:
            case NOT_EQUAL:
                compare_op.push_back(join_conditions[cond_i].comp);
                break;
            case LESS_EQUAL:
                compare_op.push_back(GREAT_EQUAL);
                break;
            case GREAT_EQUAL:
                compare_op.push_back(LESS_EQUAL);
                break;
            case LESS_THAN:
                compare_op.push_back(GREAT_THAN);
                break;
            case GREAT_THAN:
                compare_op.push_back(LESS_THAN);
                break;
            }
        }
    }

    for (int i = 0; i < this->data_length(); i++) {
        for (int j = 0; j < tuple_set.data_length(); j++) {
            TupleDataRow first_row, second_row;
            this->get_data_row(i, first_row);
            tuple_set.get_data_row(j, second_row);

            bool match = true;
            for (int cond_i = 0; cond_i < first_index.size(); cond_i++) {
                if (!match_tuple_value(first_row.get(first_index[cond_i]).get(), second_row.get(second_index[cond_i]).get(), compare_op[cond_i])) {
                    match = false;
                    break;
                }
            }

            if (match) {
                TupleDataRow new_row;
                new_row.merge_data_row(first_row);
                new_row.merge_data_row(second_row);
                final_set.add_value(new_row);
            }
        }
    }

    return final_set;
}

void TupleSet::project_tuple_set(TupleSet &tuple_set, TupleSchema &schema) {
    //记录数据的列在原始查询中的顺序
    std::vector<int> field_order_index;
    for (int i = 0; i < schema.get_length(); i++) {
        for (int j = 0; j < tuple_set.schema().get_length(); j++) {
            if (match_field(tuple_set.schema().get_field_by_index(i), schema.get_field_by_index(j))) {
                field_order_index.push_back(i);
                break;
            }
        }
    }

    for (int i = 0; i < tuple_set.data_length(); i++) {
        TupleDataRow data_row;
        tuple_set.get_data_row(i, data_row);
        data_row.copy_and_delete(field_order_index);
    }

    tuple_set.set_schema(schema);
}

void TupleSet::to_string(std::ostream &os, TupleSchema &schema) {
    //记录数据的列在原始查询中的顺序
    std::vector<int> field_order_index;
    for (int i = 0; i < schema.get_length(); i++) {
        for (int j = 0; j < this->schema().get_length(); j++) {
            if (match_field(this->schema().get_field_by_index(i), schema.get_field_by_index(j))) {
                field_order_index.push_back(j);
                break;
            }
        }
    }

    // print header
    const int cell_num = schema.get_length();
    Field field;
    for (int i = 0; i < cell_num; i++) {
        if (i != 0) {
            os << " | ";
        }
        schema.get(i, field);
        os << field.table_name() << "." << field.field_name();
    }
    if (cell_num > 0) {
        os << '\n';
    }

    // print data
    TupleDataRow data_row;
    for (int row = 0; row < data_.size(); row++) {
        get_data_row(row, data_row);
        std::shared_ptr<TupleValue> tuple_value;

        for (int i = 0; i < field_order_index.size(); i++) {
            if (i != 0) {
                os << " | ";
            }
            data_row.get(field_order_index[i], tuple_value);
            tuple_value->to_string(os);
        }

        if (cell_num > 0) {
            os << '\n';
        }
    }
}